package io.github.uicdb.et.block;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.github.uicdb.et.ModBlockEntityType;
import io.github.uicdb.et.ModElements;
import io.github.uicdb.et.capability.IElementalHandler;
import io.github.uicdb.et.capability.SimpleElementalHandler;
import io.github.uicdb.et.recipe.TurnInRecipe;
import io.github.uicdb.et.recipe.TurnInRecipeInput;
import io.netty.buffer.Unpooled;
import lombok.Getter;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.NonNullList;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.NotNull;

import java.util.function.Consumer;

@Getter
public class TurnInBlockEntity extends BaseContainerBlockEntity implements ICraft {
    public static final Codec<RecipeHolder<?>> RECIPE_HOLDER_CODEC = RecordCodecBuilder.create(
            i -> i.group(
                    ResourceLocation.CODEC.fieldOf("id").forGetter(RecipeHolder::id),
                    Recipe.CODEC.fieldOf("recipe").forGetter(RecipeHolder::value)
            ).apply(i, RecipeHolder::new)
    );
    final SimpleElementalHandler elementalHandler = new SimpleElementalHandler(4096) {
        @Override
        protected void onChange(ModElements elements, int before, int after) {
            setChanged();
        }
    };
    final ElementalContainerData elementalContainerData = new ElementalContainerData(elementalHandler);
    int recipeTime = 0;
    int maxRecipeTime = 0;
    boolean startRecipe = false;
    RecipeHolder<TurnInRecipe> currentRecipeHolder;
    final ContainerData recipeData = new ContainerData() {
        @Override
        public int get(int i) {
            return switch (i) {
                case 0 -> recipeTime;
                case 1 -> maxRecipeTime;
                default -> startRecipe ? 1 : 0;
            };
        }

        @Override
        public void set(int i, int i1) {
            if (i == 0) recipeTime = i1;
            else if (i == 1) maxRecipeTime = i1;
            else startRecipe = i1 != 0;
        }

        @Override
        public int getCount() {
            return 3;
        }
    };
    final NonNullList<ItemStack> stacks = NonNullList.withSize(2, ItemStack.EMPTY);

    public TurnInBlockEntity(BlockPos pos, BlockState blockState) {
        super(ModBlockEntityType.TURN_IN_MACHINE.get(), pos, blockState);
    }

    @Override
    public void tirggerCraft() {
        if (level != null)
            level.getRecipeManager().getRecipeFor(TurnInRecipe.TYPE, new TurnInRecipeInput(elementalHandler, stacks.get(0)), level).ifPresent(recipeHolder -> {
                if (currentRecipeHolder == null && stacks.get(1).isEmpty()) {//无合成配方,输出为空
                    currentRecipeHolder = recipeHolder;
                    maxRecipeTime = recipeHolder.value().getRecipeTime();
                    startRecipe = true;
                }
            });
    }



    private void endRecipe() {
        TurnInRecipe recipe = currentRecipeHolder.value();
        elementalHandler.drainElemental(recipe.getElement().amount(), ModElements.byHolder(recipe.getElement().element()), IElementalHandler.ElementalAction.EXECUTE);
        var result = recipe.getOutPutItem().handleRecipe(stacks.getFirst());
        stacks.set(0, stacks.getFirst().getCraftingRemainingItem());
        var input =stacks.getFirst();
        if(input.isStackable()){
            input.shrink(1);
        }else {
            stacks.set(0, stacks.getFirst().getCraftingRemainingItem());
        }
        stacks.set(1, result);
        startRecipe = false;
        currentRecipeHolder = null;
        maxRecipeTime = 0;
        recipeTime = 0;
    }

    public static void tick(Level level, BlockPos pos, BlockState state, TurnInBlockEntity turnInBlockEntity) {
        if (turnInBlockEntity.currentRecipeHolder != null) {
            turnInBlockEntity.recipeTime++;
            if (turnInBlockEntity.recipeTime == turnInBlockEntity.maxRecipeTime) {
                turnInBlockEntity.endRecipe();
            }
        }
    }

    @Override
    protected Component getDefaultName() {
        return Component.translatable("container.turn_in");
    }

    @Override
    protected NonNullList<ItemStack> getItems() {
        return stacks;
    }

    @Override
    protected void setItems(NonNullList<ItemStack> nonNullList) {
        this.stacks.clear();
        for (int i = 0; i < nonNullList.size(); i++) {
            this.stacks.set(i, nonNullList.get(i));
        }
        setChanged();
    }

    @Override
    protected @NotNull AbstractContainerMenu createMenu(int windowId, @NotNull Inventory inventory) {
        FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
        buf.writeBlockPos(getBlockPos());
        return new TurnInMenu(windowId, inventory, this, elementalContainerData, recipeData, buf);
    }

    @Override
    public int getContainerSize() {
        return stacks.size();
    }


    @Override
    protected void saveAdditional(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
        super.saveAdditional(tag, registries);
        tag.put("element", elementalHandler.serializeNBT(registries));
        ContainerHelper.saveAllItems(tag, stacks, registries);
        tag.putInt("RemainRecipeTime", recipeTime);
        tag.putBoolean("startRecipe", startRecipe);
        if (currentRecipeHolder != null) {
            tag.putString("recipe", currentRecipeHolder.id().toString());
        }
    }

    @Override
    protected void loadAdditional(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
        super.loadAdditional(tag, registries);
        elementalHandler.deserializeNBT(registries, tag.getCompound("element"));
        ContainerHelper.loadAllItems(tag, stacks, registries);
        recipeTime = tag.getInt("RemainRecipeTime");
        startRecipe = tag.getBoolean("startRecipe");
        if (tag.contains("recipe")) {
            ResourceLocation resourceLocation = ResourceLocation.parse(tag.getString("recipe"));
            if (level != null)
                level.getRecipeManager().getAllRecipesFor(TurnInRecipe.TYPE).stream()
                        .filter(s -> s.id().equals(resourceLocation)).findFirst()
                        .ifPresent(r -> currentRecipeHolder = r);
            if (currentRecipeHolder == null) {
                recipeTime = 0;
                maxRecipeTime = 0;
                startRecipe = false;
            }
        }
    }


}
